
`include "common_header.verilog"

//  *************************************************************************
//  File : mux_66
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited. 
//  Copyright (c) 2008 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Serge S., Thomas Schrobenhauser
//  info@morethanip.com
//  *************************************************************************
//  Description: Base-R PCS Receive Core : Block Sync Multiplexer.
//               Shifts the bits of the 66 bit blocks from input
//               1 cycle latency without clock-enable to be used as pipe
//               (without storage, so output will not be stable when val=0).
//  Version    : $Id: mux_661.v,v 1.1 2012/10/29 12:46:40 dk Exp $
//  *************************************************************************

module mux_661 (

   reset,
   clk,
   ck_ena,
   data_in,
   mux_data_cd,
   data_out,
   sh_out,
   sync_tst,
   data_out_val);

input   reset;                  //  asynch reset
input   clk;                    //  system clock
input   ck_ena;                 //  clock enable
input   [65:0] data_in;         //  Data input
input   [6:0] mux_data_cd;      //  Command of Sync Header Mux
output  [63:0] data_out;        //  Data out
output  [1:0] sh_out;           //  Sync header
output  [1:0] sync_tst;         //  Sync header
output  data_out_val;           //  output valid, following ck_ena

reg     [63:0] data_out; 
reg     [1:0] sh_out; 
reg     [1:0] sync_tst; 
reg     data_out_val;           //  output valid, following ck_ena

reg     [65:0] data_in_s1;      //  data input
reg     [65 + 15:0] data_in_s1b; //  data input, first mux stage
reg     [65:0] data_in_s2;      //  data input
wire    [2:0] mux_hi;           //  first 8 subsections with 16 shifts each
wire    [3:0] mux_lo;           //  16 within subsection

// - 65....0  65....0 
// - data_in  _s1
// - _s1b
// - _s2

//  first stage, shift input in steps of 16
//  0, 16, 32, 48, 64
//  ---------------------------------------

assign mux_hi = mux_data_cd[6:4]; 

always @(posedge clk or posedge reset)
   begin : p_s1
   if (reset == 1'b 1)
      begin
      data_in_s1 <= {66{1'b 0}};
      end
   else
      begin

      if (ck_ena == 1'b 1)
         begin
         data_in_s1 <= data_in;	
         end

      end
   end

always @(mux_hi or data_in or data_in_s1)
   begin : c_s1
         case (mux_hi)
         3'b 000:
            begin
            data_in_s1b = {data_in[65:0], data_in_s1[65:66 - 16 + 1]};	
            end
         3'b 001:
            begin
            data_in_s1b = {data_in[65 - 16:0], data_in_s1[65:66 - 32 + 1]};	
            end
         3'b 010:
            begin
            data_in_s1b = {data_in[65 - 32:0], data_in_s1[65:66 - 48 + 1]};	
            end
         3'b 011:
            begin
            data_in_s1b = {data_in[65 - 48:0], data_in_s1[65:66 - 64 + 1]};	
            end
         3'b 100:
            begin
            data_in_s1b = {data_in[65 - 64:0], data_in_s1[65:0], 13'b 0000000000000};	
            end
         default:
            begin
            data_in_s1b = {data_in[65 - 64:0], data_in_s1[65:0], 13'b 0000000000000};	
            end
         endcase
   end

//  2nd stage, shift 16 within word

assign mux_lo = mux_data_cd[3:0];	

always @(mux_lo or data_in_s1b)
begin
         case (mux_lo)
         4'b 0000:
            begin
            data_in_s2 = data_in_s1b[65 + 15:15];	
            end
         4'b 0001:
            begin
            data_in_s2 = data_in_s1b[65 + 14:14];	
            end
         4'b 0010:
            begin
            data_in_s2 = data_in_s1b[65 + 13:13];	
            end
         4'b 0011:
            begin
            data_in_s2 = data_in_s1b[65 + 12:12];	
            end
         4'b 0100:
            begin
            data_in_s2 = data_in_s1b[65 + 11:11];	
            end
         4'b 0101:
            begin
            data_in_s2 = data_in_s1b[65 + 10:10];	
            end
         4'b 0110:
            begin
            data_in_s2 = data_in_s1b[65 + 9:9];	
            end
         4'b 0111:
            begin
            data_in_s2 = data_in_s1b[65 + 8:8];	
            end
         4'b 1000:
            begin
            data_in_s2 = data_in_s1b[65 + 7:7];	
            end
         4'b 1001:
            begin
            data_in_s2 = data_in_s1b[65 + 6:6];	
            end
         4'b 1010:
            begin
            data_in_s2 = data_in_s1b[65 + 5:5];	
            end
         4'b 1011:
            begin
            data_in_s2 = data_in_s1b[65 + 4:4];	
            end
         4'b 1100:
            begin
            data_in_s2 = data_in_s1b[65 + 3:3];	
            end
         4'b 1101:
            begin
            data_in_s2 = data_in_s1b[65 + 2:2];	
            end
         4'b 1110:
            begin
            data_in_s2 = data_in_s1b[65 + 1:1];	
            end
         4'b 1111:
            begin
            data_in_s2 = data_in_s1b[65 + 0:0];	
            end
         default:
            begin
            data_in_s2 = data_in_s1b[65 + 0:0];	
            end
         endcase
   end

// register at output, not using ck_ena to make it a plain pipeline.
// ------------------
always @(posedge clk or posedge reset)
   begin : p_out
   if (reset == 1'b 1)
      begin
      data_out  <= {64{1'b 0}};
      sh_out    <= 2'b 00;
      sync_tst  <= 2'b 00;
      data_out_val <= 1'b 0;
      end
   else // NO ck_ena here!
      begin

      data_out  <= data_in_s2[65:2];
      sh_out    <= data_in_s2[1:0]; 
      sync_tst  <= data_in_s2[1:0]; 
      
      data_out_val <= ck_ena;   // valid output on next cycle

      end
   end

endmodule // module mux_66
